/*
 * Copyright 2014 OGIS-RI All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jp.co.ogis_ri.optaplanner.vehiclerouting.domain.core;

import jp.co.ogis_ri.optaplanner.vehiclerouting.domain.Vehicle;
import jp.co.ogis_ri.optaplanner.vehiclerouting.domain.solver.ArrivalTimeUpdatingVariableListener;
import jp.co.ogis_ri.optaplanner.vehiclerouting.domain.solver.VehicleUpdatingVariableListener;
import jp.co.ogis_ri.optaplanner.vehiclerouting.domain.solver.VrpCargoDifficultyComparator;

import org.optaplanner.core.api.domain.entity.PlanningEntity;
import org.optaplanner.core.api.domain.variable.CustomShadowVariable;
import org.optaplanner.core.api.domain.variable.PlanningVariable;
import org.optaplanner.core.api.domain.variable.PlanningVariableGraphType;

/**
 * 荷物
 * 
 */
@PlanningEntity(difficultyComparatorClass = VrpCargoDifficultyComparator.class)
abstract public class ChainedTimeWindowedStep extends TimeWindowedStep {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * Shadow variable: 到着時間 {@link ArrivalTimeUpdatingVariableListener} にて設定される
	 */
	protected Integer arrivalTime;

	/**
	 * Planning variables: この Cargoの前にくるもの
	 */
	protected TimeWindowedStep previousStep;

	/**
	 * Shadow variable: このCargoを担当するVehicle
	 * {@link VehicleUpdatingVariableListener} にて設定される
	 */
	protected Vehicle vehicle;

	/**
	 * Planning variables: この Cargoの前にくるものを取得する
	 * 
	 * @return
	 */
	@PlanningVariable(valueRangeProviderRefs = { "vehicleRange", "cargoRange" }, graphType = PlanningVariableGraphType.CHAINED)
	public TimeWindowedStep getPreviousStep() {
		return this.previousStep;
	}

	/**
	 * Planning variables: この Cargoの前にくるものを設定する
	 * 
	 * @param previousStep
	 */
	public void setPreviousStep(final TimeWindowedStep previousStep) {
		this.previousStep = previousStep;
	}

	/**
	 * Shadow variable: このCargoを担当するVehicleを取得する
	 * {@link VehicleUpdatingVariableListener} にて設定される
	 */
	@Override
	@CustomShadowVariable(variableListenerClass = VehicleUpdatingVariableListener.class, sources = { @CustomShadowVariable.Source(variableName = "previousStep") })
	public Vehicle getVehicle() {
		return this.vehicle;
	}

	/**
	 * Shadow variable: このCargoを担当するVehicleを設定する
	 * {@link VehicleUpdatingVariableListener} にて設定される
	 */
	public void setVehicle(final Vehicle vehicle) {
		this.vehicle = vehicle;
	}

	/**
	 * Shadow variable: 到着時間を取得する {@link ArrivalTimeUpdatingVariableListener}
	 * にて設定される
	 * 
	 * @return
	 */
	@CustomShadowVariable(variableListenerClass = ArrivalTimeUpdatingVariableListener.class, sources = { @CustomShadowVariable.Source(variableName = "previousStep") })
	public Integer getArrivalTime() {
		return this.arrivalTime;
	}

	/**
	 * Shadow variable: 到着時間を設定する {@link ArrivalTimeUpdatingVariableListener}
	 * にて設定される
	 * 
	 * @param arrivalTime
	 */
	public void setArrivalTime(final Integer arrivalTime) {
		this.arrivalTime = arrivalTime;
	}

	// ************************************************************************
	// Complex methods
	// ************************************************************************

	/**
	 * ひとつ前の地点からの距離を取得する
	 * 
	 * @return
	 */
	abstract public int getDistanceToPreviousStep();

	/**
	 * ひとつ前の地点からの移動時間を取得する
	 * 
	 * @return
	 */
	abstract public int getTravelTimeToPreviousStep();

	/**
	 * 指定された地点からの距離を取得する
	 * 
	 * @param step
	 * @return
	 */
	abstract public int getDistanceTo(final TimeWindowedStep step);

	/**
	 * 指定された地点からの移動時間を取得する
	 * 
	 * @param step
	 * @return
	 */
	abstract public int getTravelTimeTo(final TimeWindowedStep step);
}
